home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
rpg
/
crossfir.92
/
crossfir
/
crossfire-0.92.5
/
server
/
socket.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-24
|
10KB
|
362 lines
/*
* static char *rcsid_sockets_c =
* "$Id: socket.c,v 1.28 1995/04/15 05:03:12 master Exp $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author can be reached via e-mail to frankj@ifi.uio.no.
*/
/*
* The routines in socket.c were mainly written by eanders+@cmu.edu
* I moved them to a separate file, since main() got too clobbered. -Frank.
*/
#include <global.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
#ifdef SERVER
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#if defined(hpux) || defined(SVR4)
#include <unistd.h>
#endif
#if defined(_IBMR2) || defined(___IBMR2)
#include <sys/select.h>
#endif
#if defined(__sun__) && !defined(SVR4)
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
#endif
int max_filedescriptors = 0;
struct timeval timeout;
int acceptfd,pollret;
struct protoent *protox;
struct sockaddr_in insock;
struct sockaddr_in addr;
int addrlen=sizeof(struct sockaddr);
int doneone=0;
unsigned short listen_port = PORT;
#endif /* SERVER */
void init_socket() {
#ifdef SERVER
if(server_mode == SERVER_ENABLED || debug)
LOG(llevError,"Opening add user socket on %d\n",listen_port);
#if defined(hpux) || defined (SVR4)
max_filedescriptors = sysconf(_SC_OPEN_MAX);
#else
max_filedescriptors = getdtablesize();
#endif
timeout.tv_sec = 0;
timeout.tv_usec = 0;
protox = getprotobyname("tcp");
if (protox==NULL) {
LOG(llevError,"Error getting protobyname\n");
exit(1);
}
acceptfd = socket(PF_INET,SOCK_STREAM,protox->p_proto);
if (acceptfd == (-1)) {
perror("error on socket command");
exit(-1);
}
insock.sin_family = AF_INET;
insock.sin_port = htons(listen_port);
insock.sin_addr.s_addr = htonl(INADDR_ANY);
{
struct linger linger_opt;
linger_opt.l_onoff = 0;
linger_opt.l_linger = 0;
if(setsockopt(acceptfd,SOL_SOCKET,SO_LINGER,(char *) &linger_opt,
sizeof(struct linger)))
perror("error on setsockopt LINGER");
}
#if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
defined(__sun__) || defined(linux) || defined(SVR4)
{
char tmp =1;
if(setsockopt(acceptfd,SOL_SOCKET,SO_REUSEADDR, &tmp, sizeof(&tmp)))
perror("error on setsockopt REUSEADDR");
}
#else
if(setsockopt(acceptfd,SOL_SOCKET,SO_REUSEADDR,(char *)NULL,0))
perror("error on setsockopt REUSEADDR");
#endif
if (bind(acceptfd,(struct sockaddr *)&insock,sizeof(insock)) == (-1)) {
if(server_mode == SERVER_ENABLED || debug)
perror("error on bind command");
abort_sockets();
return;
}
if (listen(acceptfd,5) == (-1)) {
perror("error on listen");
abort_sockets();
return;
}
if(server_mode == SERVER_ENABLED)
block_until_new_connection();
#endif
}
void check_socket() {
#ifdef SERVER
fd_set tmp_read;
fd_set tmp_exceptions;
sockets *next=NULL;
if(server_mode == SERVER_DISABLED)
return;
FD_ZERO(&tmp_read);
FD_ZERO(&tmp_exceptions);
for(active_socket = first_socket; active_socket != (sockets *) NULL;
active_socket = active_socket->next) {
FD_SET(active_socket->fd,&tmp_read);
FD_SET(active_socket->fd,&tmp_exceptions);
}
FD_SET(acceptfd,&tmp_read);
pollret = select(max_filedescriptors,&tmp_read,NULL,&tmp_exceptions,&timeout);
if (pollret == (-1)) {
perror("select");
return;
}
if (!pollret) /* Nothing new */
return;
if (FD_ISSET(acceptfd,&tmp_read)) { /* try to accept any new connections */
int fd = accept(acceptfd,(struct sockaddr *)&addr,&addrlen);
if (fd == (-1))
perror("accept");
else {
unsigned long from = ntohl(addr.sin_addr.s_addr);
add_socket(fd, from);
}
}
for(active_socket = first_socket; active_socket != (sockets *) NULL;
active_socket = next) {
next = active_socket->next;
if(FD_ISSET(active_socket->fd,&tmp_exceptions)) {
LOG(llevError,"Exception received at %d\n",active_socket->fd);
remove_socket(active_socket);
continue;
}
if(FD_ISSET(active_socket->fd,&tmp_read)) {
int readct;
char buf[SOCKET_BUFLEN+1];
/* Have input */
readct = read(active_socket->fd,buf,SOCKET_BUFLEN);
if(readct == (-1)) {
perror("read");
continue;
}
if (readct==0) {
close(active_socket->fd);
remove_socket(active_socket);
if (server_mode == SERVER_ABORTED) {
LOG(llevError, "Server mode ended.\n");
server_mode = SERVER_OFF;
}
} else {
/* The following should never ever happen. */
if (readct>SOCKET_BUFLEN) {
if(debug)
LOG(llevError,"Error, Protocol Violation, input too long\n");
draw_socket(active_socket->fd,"Line too long, ignored.");
/* Having this be fatal probably does not make much
* difference - if the buffer was overflowed, various
* areas of data will be corrupted in any case.
*/
/*return; *//* Why should this be fatal??? */
continue;
}
buf[readct]='\0';
if (buf[readct-1] == '\n')
buf[--readct] = '\0';
if (buf[readct-1] == '\r')
buf[--readct] = '\0';
if (debug) /* Would get useless echos if I used LOG() here */
if (strncmp(buf, "dm ", 3)) /* Better not log the password */
fprintf(logfile,"socket[%s]: %s\n",active_socket->name,buf);
if(buf[0]=='\0')
continue; /* Empty line */
parse_string(NULL,buf);
if (active_socket->quit == 1)
{
close(active_socket->fd);
remove_socket(active_socket);
}
}
}
}
active_socket = (sockets *) NULL;
#endif /* SERVER */
}
void add_socket(int fd, unsigned long from) {
#ifdef SERVER
sockets *socket = (sockets *) malloc(sizeof(sockets));
socket->fd = fd;
sprintf(socket->host,"%ld.%ld.%ld.%ld",
(from>>24)&255, (from>>16)&255, (from>>8)&255, from&255);
LOG(llevDebug, "Adding socket %d from %s.\n",fd,socket->host);
socket->listen_lev = 8;
socket->wiz = 0;
socket->use_pix = 0;
socket->color_pix = 0;
socket->split = 0;
socket->debug = llevError;
socket->protocol = 0;
socket->quit = 0;
socket->next = first_socket;
first_socket = socket;
if(fd>9999 || fd < 0)
strcpy(socket->name,"anonym");
else
sprintf(socket->name,"anon%d",fd);
draw_socket(socket->fd, "Welcome to a crossfire server. Type 'help' if you need help.");
#endif
}
void set_protocol(sockets *s, int p) {
if (p < 0 || p > 1) {
char buf[MAX_BUF];
sprintf(buf,"Invalid protocol, accepted protocols are: 0 1");
draw_socket(s->fd, buf);
}
s->protocol = p;
draw_socket(s->fd, "OK.");
}
void remove_socket(sockets *socket) {
#ifdef SERVER
sockets *tmp, *prev = NULL;
for(tmp = first_socket; tmp != NULL; prev = tmp, tmp = tmp->next)
if(tmp == socket)
break;
if(tmp == NULL) {
LOG(llevError,"remove_socket: no such socket\n");
return;
}
if(prev == NULL)
first_socket = tmp->next;
else
prev->next = tmp->next;
LOG(llevDebug,"Removing socket %d\n",tmp->fd);
free(tmp);
if (first_player == (player *) NULL &&
first_socket == (sockets *) NULL && server_mode == SERVER_ENABLED)
block_until_new_connection();
#endif
}
void close_all_sockets() {
#ifdef SERVER
info_all_sockets("Crossfire died, disconnecting...");
server_mode = SERVER_ABORTED; /* Don't want to block */
while(first_socket != (sockets *) NULL) {
close(first_socket->fd);
remove_socket(first_socket);
}
#endif
}
void draw_socket(int fd, const char *str) {
#ifdef SERVER
int i=0,len;
char *buf = (char *) malloc(sizeof(char) * strlen(str) + 2);
strcpy(buf,str);
strcat(buf,"\n");
str = buf;
while ((len = strlen(str))) {
i=write(fd,str,len);
if(i < 0) {
perror("draw_socket");
break;
}
else if (i != len) {
LOG(llevDebug, "draw_socket: write returned %d of %d\n", i, len);
} else
str+=i;
}
free(buf);
#endif
}
void info_all_sockets(char *txt) {
#if defined(SERVER)
sockets *s;
for(s = first_socket; s != (sockets *) NULL; s = s->next)
if (s->protocol != 1 && s->listen_lev>0)
draw_socket(s->fd,txt);
#endif
}
void abort_sockets() {
#ifdef SERVER
if(server_mode != SERVER_ENABLED) {
LOG(llevDebug,"Turning off sockets.\n");
if(close(acceptfd))
perror("Disabling sockets/close");
server_mode = SERVER_DISABLED; /* No need to check them in the future */
return;
}
exit(1);
#endif
}
void block_until_new_connection()
{
#ifdef SERVER
fd_set readfs;
FD_ZERO(&readfs);
FD_SET(acceptfd, &readfs);
#if ERIC_SERVER
FD_SET(ericfd(),&readfs);
#endif
LOG(llevError, "Waiting for connections...\n");
(void) select(max_filedescriptors, &readfs, NULL, NULL, NULL);
reset_sleep(); /* Or the game would go too fast */
#endif
}